#include "RegionManager.h"

#include <algorithm>

#include <wx/textfile.h>
#include <wx/msgdlg.h>
#include <wx/file.h>
#include <wx/log.h>
#include <wx/tokenzr.h>
#include <wx/filename.h>

RegionField::RegionField(int id, int parentId)
    :m_id(id), m_parentId(parentId)
{

}


bool RegionField::MatchName(const wxString& name, bool wholeWord) const
{
    for( auto itr = m_langName.begin(); itr != m_langName.end(); ++itr )
    {
        const wxString & fieldName = itr->second;
        if( wholeWord )
        {
            if( fieldName.Lower() == name.Lower() ) return true;
        }
        else
        {
            if( fieldName.Lower().Find(name.Lower()) != wxNOT_FOUND ) return true;
        }
    }
    return false;
}


bool RegionField::MatchName(const RegionField& field) const
{
    for( auto itr=field.m_langName.begin(); itr != field.m_langName.end(); ++itr )
    {
        if( MatchName(itr->second, true) )
        {
            return true;
        }
    }
    return false;
}


void RegionField::AddChildId(int childId)
{
    if( find(m_childrenId.begin(), m_childrenId.end(), childId) ==
        m_childrenId.end() )
        m_childrenId.push_back(childId);
}

wxString RegionField::GetDumpData(int maxLangId)
{
    wxString data;
    for( auto itr = m_langName.begin(); itr != m_langName.end(); ++itr )
    {
        if( itr->first < maxLangId )data += wxString::Format(wxT("%d|%d|%d|%s|\n"),
                    m_id, itr->first, m_parentId, itr->second.c_str());
    }
    return data;
}

bool Region::MatchName(const wxString& name) const
{
    if( m_country.MatchName(name) ) return true;
    if( m_province.MatchName(name) ) return true;
    if( m_city.MatchName(name) ) return true;
    return false;
}


bool RegionManager::Load(const wxString& fileName)
{
    wxTextFile file(fileName);
    if( !file.Open() )
    {
        wxLogError(wxT("Open file '%s' error!"), fileName.c_str());
    }
    m_regionFields.clear();
    m_regionFields.insert(make_pair(0, RegionField(0, 0)));
    for( wxString line = file.GetFirstLine();
        !file.Eof(); line = file.GetNextLine() )
    {
        wxStringTokenizer tkz(line, wxT("|"));
        long id, parentId, langId;
        wxString name;
        if( !tkz.GetNextToken().ToLong(&id) )
        {
            wxLogError(wxT("%s to id fail!"), line.c_str());
            return false;
        }
        if( !tkz.GetNextToken().ToLong(&langId) )
        {
            wxLogError(wxT("%s to lang_id fail!"), line.c_str());
            return false;
        }
        if( !tkz.GetNextToken().ToLong(&parentId) )
        {
            wxLogError(wxT("%s to parent_id fail!"), line.c_str());
            return false;
        }
        name = tkz.GetNextToken();

        auto idAndField = m_regionFields.find(id);
        if( idAndField == m_regionFields.end() )
        {
            m_regionFields.insert(make_pair(id, RegionField(id, parentId)));
            idAndField = m_regionFields.find(id);
        }
        idAndField->second.SetName(langId, name);
    }

    for( auto itr = m_regionFields.begin(); itr != m_regionFields.end(); ++itr )
    {
        if( itr->first == 0 ) continue;
        int parentId = itr->second.GetParentId();
        int id = itr->second.GetId();
        auto parentIdAndField = m_regionFields.find(parentId);
        if( parentIdAndField == m_regionFields.end() || parentIdAndField->second.GetId() != parentId )
        {
            wxLogError(wxT("Can't find parent id: %d of id %d"), parentId, id);
            return false;
        }
        parentIdAndField->second.AddChildId(id);
    }
    return true;
}

vector<Region> RegionManager::GetRegions(const wxString& filter)
{
    vector<Region> res;
    RegionField & root = m_regionFields[0];
    //wxLogMessage(wxString::Format(wxT("country count: %u"), root.GetChildrenId().size()));
    for(int countryId: root.GetChildrenId())
    {
        Region region;
        region.SetCountry(m_regionFields[countryId]);
        res.push_back(region);
        for(int provinceId: region.GetCountry().GetChildrenId())
        {
            region.SetProvince(m_regionFields[provinceId]);
            res.push_back(region);
            for(int cityId: region.GetProvince().GetChildrenId())
            {
                region.SetCity(m_regionFields[cityId]);
                res.push_back(region);
            }
            region.SetCity(RegionField());
        }
        region.SetProvince(RegionField());
    }
    vector<Region> afterFilter;
    for(const Region & region: res)
    {
        if( region.MatchName(filter) ) afterFilter.push_back(region);
    }
    return afterFilter;
}

int RegionManager::Save(const wxString& dir)
{
    if(!wxFileName::DirExists(dir))
    {
        wxLogError(wxT("dir not exists"), dir.c_str());
        return -1;
    }
    wxDateTime now = wxDateTime::Now();
    wxString timeSuffix = wxString::Format(wxT("%d_%d_%d_%d_%d"),
            now.GetYear(), now.GetMonth()+1, now.GetDay(), now.GetHour(), now.GetMinute());
    if( SaveServer(wxString::Format(wxT("%s/server_data_%s"), dir.c_str(), timeSuffix.c_str())) != 0 )
    {
        wxLogError(wxT("save server data error!"));
        return -2;
    }

    //if( SaveAndroid(wxString::Format(wxT("%s/android_data_%s"), dir.c_str(), timeSuffix.c_str())) != 0 )
    //{
     //   wxLogError(wxT("save android data error!"));
    //    return -2;
   // }

    wxMessageBox(wxT("保存成功！！"));
    return 0;
}

int RegionManager::SaveData(const wxString& fileName, int maxLangId)
{
    wxFile file(fileName.c_str(), wxFile::write);
    if( !file.IsOpened() )
    {
        wxLogError(wxT("Create file %s error!"), fileName.c_str());
        return -1;
    }
    vector<RegionField*> fields;
    for( auto itr = m_regionFields.begin(); itr != m_regionFields.end(); ++itr )
    {
        fields.push_back(&itr->second);
    }
    for(RegionField * field: fields)
    {
        file.Write(field->GetDumpData(maxLangId));
    }
    file.Close();
    return 0;
}

int RegionManager::SaveServer(const wxString& fileName)
{
    return SaveData(fileName);
}

int RegionManager::SaveAndroid(const wxString& fileName)
{
    return SaveData(fileName, 999);
}

RegionField * RegionManager::GetRegionById(int id)
{
    if( m_regionFields.find(id) != m_regionFields.end() )
    {
        return &m_regionFields[id];
    }
    else
    {
        return NULL;
    }
}

int RegionManager::UpdateField(int fieldId, int langId, const wxString& fieldName)
{
    if( m_regionFields.find(fieldId) == m_regionFields.end() )
    {
        wxLogError(wxT("ERR %s: can't find id: %u in manager!"), __func__, fieldId);
        return -1;
    }
    RegionField & field = m_regionFields.find(fieldId)->second;
    RegionField & parentField = m_regionFields.find(field.GetParentId())->second;
    for( int childId: parentField.GetChildrenId() )
    {
        RegionField & childField = m_regionFields.find(childId)->second;
        if( childField.GetId() == fieldId ) continue;
        if( childField.MatchName(fieldName, true) )
        {
            wxLogError(wxT("ERR  RegionManager::UpdateField: 节点(%s)的子节点中已经有节点(%s) 能匹配(%s)这个名字"),
                parentField.GetName(SIMPLE_CHINESE).c_str(), childField.GetName(SIMPLE_CHINESE).c_str(),
                fieldName.c_str());
            return -2;
        }
    }
    wxString oldName = field.GetName(langId);
    field.SetName(langId, fieldName);
    if( !field.MatchName(oldName, true) )
    {
        for( int newLangId = 1000; newLangId; ++newLangId )
        {
            if( !field.HasLang(newLangId) )
            {
                field.SetName(newLangId, oldName);
                break;
            }
        }
    }
    return 0;
}

int RegionManager::CreateField(Region * region)
{
        bool cnEmpty = region->GetCountry().IsEmpty();
        bool pvEmtpy = region->GetProvince().IsEmpty();
        bool ctEmpty = region->GetCity().IsEmpty();
        if( cnEmpty )
        {
            wxLogError(wxT("国家不能为空！"));
            return -1;
        }
        else if( pvEmtpy )
        {
            if( !ctEmpty )
            {
                wxLogError(wxT("省份不能为空！"));
                return -1;
            }
        }
    if( region->GetCountry().GetId() == 0 )
    {
        for( const RegionField * country: GetCountries() )
        {
            if( country->MatchName(region->GetCountry()) )
            {
                wxLogError(wxT("名字冲突，已有国家的名字包含 '%s'"), region->GetCountry().GetName(REGION_CODE).c_str());
                return -1;
            }
        }
        int countryId = 1000;
        while( m_regionFields.find(countryId) != m_regionFields.end() ) ++countryId;
        region->GetMutableCountry()->SetId(countryId);
        m_regionFields[0].AddChildId(countryId);
        wxLogMessage(wxT("创建了一个国家：%s, 新id：%d"), region->GetCountry().GetLogName().c_str(), countryId);
    }
    if( region->GetProvince().GetId() == 0 )
    {
        int countryId = region->GetCountry().GetId();
        for( const RegionField * existProvince: GetProvinces(countryId) )
        {
            if( existProvince->MatchName(region->GetProvince()) )
            {
                wxLogError(wxT("名字冲突，已有省份的名字包含 '%s'"), region->GetProvince().GetName(REGION_CODE).c_str());
                return -1;
            }
        }
        int provinceId = 10000;
        while( m_regionFields.find(provinceId) != m_regionFields.end() ) ++provinceId;
        region->GetMutableProvince()->SetId(provinceId);
        m_regionFields[countryId].AddChildId(provinceId);
        wxLogMessage(wxT("创建了一个省份：%s, 新id：%d"), region->GetProvince().GetLogName().c_str(), provinceId);
    }
    if( region->GetCity().GetId() == 0 )
    {
        int provinceId = region->GetProvince().GetId();
        for( const RegionField * existCity: GetCities(provinceId) )
        {
            if( existCity->MatchName(region->GetCity()) )
            {
                wxLogError(wxT("名字冲突，已有城市的名字包含 '%s'"), region->GetCity().GetName(REGION_CODE).c_str());
                return -1;
            }
        }
        int cityId = 100000;
        while( m_regionFields.find(cityId) != m_regionFields.end() ) ++cityId;
        region->GetMutableCity()->SetId(cityId);
        m_regionFields[provinceId].AddChildId(cityId);
        wxLogMessage(wxT("创建了一个城市：%s, 新id：%d"), region->GetCity().GetLogName().c_str(), cityId);
    }
    return 0;
}


vector<const RegionField *> RegionManager::GetCountries()
{
    vector<const RegionField *> countries;
    for( int childId: m_regionFields[0].GetChildrenId() )
    {
        countries.push_back(&m_regionFields[childId]);
    }
    return countries;
}

vector<const RegionField *> RegionManager::GetProvinces(int countryId)
{
    vector<const RegionField *> provinces;
    if( countryId < 1000 || countryId >= 10000 )
    {
        wxLogError(wxT("RegionManager::GetProvinces: wrong country id: %d"), countryId);
        return provinces;
    }
    for( int childId: m_regionFields[countryId].GetChildrenId() )
    {
        provinces.push_back(&m_regionFields[childId]);
    }
    return provinces;
}

vector<const RegionField *> RegionManager::GetCities(int provinceId)
{
    vector<const RegionField *> cities;
    if( provinceId < 10000 || provinceId >= 100000 )
    {
        wxLogError(wxT("RegionManager::GetCities: wrong province id: %d"), provinceId);
        return cities;
    }
    for( int childId: m_regionFields[provinceId].GetChildrenId() )
    {
        cities.push_back(&m_regionFields[childId]);
    }
    return cities;
}

